﻿using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;


namespace GMC_4
{
    public partial class Form1 : Form
    {
        Vm vm = new Vm(Assembler.Assemble(""));
        Timer timer = new Timer();

        public Form1()
        {
            InitializeComponent();
            timer.Interval = 10;
            timer.Tick += new EventHandler(timer_Tick);
            InitDisplay();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            StepVm();
            UpdateDisplay();
        }

        private void compileButton_Click(object sender, EventArgs e)
        {
            StopVm();

            try
            {
                byte[] code = Assembler.Assemble(sourceTextBox.Text);
                vm = new Vm(code);
                errorTextBox.Text = @"(\/)O_o(\/) - Compilation succeeded!";
            }
            catch (System.Exception ex)
            {
                errorTextBox.Text = ex.ToString();
            }

            UpdateDisplay();
        }

        private void stepButton_Click(object sender, EventArgs e)
        {
            StopVm();
            StepVm();
            UpdateDisplay();
        }

        private void runButton_Click(object sender, EventArgs e)
        {
            if (timer.Enabled)
                StopVm();
            else
                StartVm();
        }

        private void StartVm()
        {
            timer.Start();
            runButton.Text = "pause";
        }

        private void StopVm()
        {
            timer.Stop();
            runButton.Text = "run";
        }

        private void StepVm()
        {
            try
            {
                vm.Step();
            }
            catch (System.Exception ex)
            {
                errorTextBox.Text = ex.ToString();
                StopVm();
            }
        }

        private void InitDisplay()
        {
            string[] disassembly = Disassembler.Disassemble(vm.M);
            for (int i = 0; i < 0x20; ++i)
                disassembly1ListBox.Items.Add(disassembly[i]);
            for (int i = 0x20; i < 0x40; ++i)
                disassembly2ListBox.Items.Add(disassembly[i]);
            for (int i = 0x40; i < 0x60; ++i)
                disassembly3ListBox.Items.Add(disassembly[i]);
        }

        private void UpdateDisplay()
        {
            string[] disassembly = Disassembler.Disassemble(vm.M);
            for (int i = 0; i < 0x20; ++i)
            {
                if (disassembly[i] != (string)disassembly1ListBox.Items[i])
                    disassembly1ListBox.Items[i] = disassembly[i];
            }
            for (int i = 0x20; i < 0x40; ++i)
            {
                if (disassembly[i] != (string)disassembly2ListBox.Items[i - 0x20])
                    disassembly2ListBox.Items[i-0x20] = disassembly[i];
            }
            for (int i = 0x40; i < 0x60; ++i)
            {
                if (disassembly[i] != (string)disassembly3ListBox.Items[i - 0x40])
                    disassembly3ListBox.Items[i - 0x40] = disassembly[i];
            }

            disassembly1ListBox.SelectedIndex = -1;
            disassembly2ListBox.SelectedIndex = -1;
            disassembly3ListBox.SelectedIndex = -1;
            if (vm.Pc < 0x20)
                disassembly1ListBox.SelectedIndex = vm.Pc;
            else if (vm.Pc < 0x40)
                disassembly2ListBox.SelectedIndex = vm.Pc - 0x20;
            else if (vm.Pc < 0x60)
                disassembly3ListBox.SelectedIndex = vm.Pc - 0x40;

            mainRegistersLabel.Text = string.Format("A ={0:X}   B ={1:X}   Y ={2:X}   Z ={3:X}", vm.A, vm.B, vm.Y, vm.Z);
            auxiliaryRegistersLabel.Text = string.Format("A'={0:X}   B'={1:X}   Y'={2:X}   Z'={3:X}", vm.Aa, vm.Bb, vm.Yy, vm.Zz);
            pcLabel.Text = string.Format("Pc={0:X2}", vm.Pc);
            ledLabel.Text = string.Format(Disassembler.ValueToLed(vm.LED));
            sevenSegmentDisplayLabel.Text = (vm.SevenSegmentDisplay == 0xff) ? " " : vm.SevenSegmentDisplay.ToString("X");
            StatusLabel.Text = string.Format("Status= {0}", vm.Status ? 1 : 0);
        }

        private void disassemblyListBox_DrawItem(object sender, DrawItemEventArgs e)
        {
            ListBox lb = (ListBox)sender;

            int baseAddress;
            if (lb == disassembly1ListBox)
                baseAddress = 0;
            else if (lb == disassembly2ListBox)
                baseAddress = 0x20;
            else
                baseAddress = 0x40;

            Graphics g = e.Graphics;
            int index = e.Index;
            string text = lb.Items[index].ToString();

            Brush foreground, background;
            if ((e.Index + baseAddress) == vm.Pc)
            {
                foreground = Brushes.White;
                background = Brushes.DarkRed;
            }
            else
            {
                foreground = Brushes.Black;
                // Program memory
                if (index + baseAddress < 0x50)
                {
                    if (((index / 4) & 1) == 1)
                        background = Brushes.Wheat;
                    else
                        background = Brushes.Cornsilk;
                }
                // Data memory
                else
                {
                    if (((index / 4) & 1) == 1)
                        background = Brushes.DarkSeaGreen;
                    else
                        background = Brushes.PaleGreen;
                }
            }
            g.FillRectangle(background, e.Bounds);
            g.DrawString(text, e.Font, foreground, lb.GetItemRectangle(index).Location);

            e.DrawFocusRectangle();
        }

        private void copyButton_Click(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            foreach (string s in disassembly1ListBox.Items)
                sb.AppendLine(s);
            foreach (string s in disassembly2ListBox.Items)
                sb.AppendLine(s);
            foreach (string s in disassembly3ListBox.Items)
                sb.AppendLine(s);
            Clipboard.SetText(sb.ToString());
        }

    }
}
